package edu.vt.ece.rt.benchmark.labyrinth;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Maze {

	
    Grid gridPtr;
    Queue<Pair> workQueuePtr;   /* contains source/destination pairs to route */
    ArrayList<Coordinate> wallVectorPtr; /* obstacles */
    ArrayList<Coordinate> srcVectorPtr;  /* sources */
    ArrayList<Coordinate> dstVectorPtr;  /* destinations */

    Maze() {
    	workQueuePtr = new LinkedList<Pair>();
    	wallVectorPtr = new ArrayList<Coordinate>();
    	srcVectorPtr = new ArrayList<Coordinate>();
    	dstVectorPtr = new ArrayList<Coordinate>();
    }
    
    /* =============================================================================
     * addToGrid
     * =============================================================================
     */
    static void
    addToGrid (Grid gridPtr, ArrayList<Coordinate> vectorPtr, String type)
    {
        for (Coordinate coordinatePtr: vectorPtr) {
            if (!Grid.grid_isPointValid(gridPtr,
                                   coordinatePtr.x,
                                   coordinatePtr.y,
                                   coordinatePtr.z))
            {
                
            }
        }
        Grid.grid_addPath(gridPtr, vectorPtr);
    }


    /* =============================================================================
     * maze_read
     * -- Return number of path to route
     * =============================================================================
     */
    static void
    maze_read (Maze mazePtr, String inputFileName) throws IOException
    {
    	
    	FileInputStream fstream = new FileInputStream(inputFileName);
    	DataInputStream in = new DataInputStream(fstream);
    	BufferedReader br = new BufferedReader(new InputStreamReader(in));

    	String strLine;
    	
        /*
         * Parse input file
         */
        long height = -1;
        long width  = -1;
        long depth  = -1;
        ArrayList<Pair> workListPtr = new ArrayList<Pair>();
        ArrayList<Coordinate> wallVectorPtr = mazePtr.wallVectorPtr;
        ArrayList<Coordinate> srcVectorPtr = mazePtr.srcVectorPtr;
        ArrayList<Coordinate> dstVectorPtr = mazePtr.dstVectorPtr;

    	while ((strLine = br.readLine()) != null) {
    		
    		StringTokenizer tokens = new StringTokenizer(strLine);
    		
    		if (!tokens.hasMoreElements())
    			continue;
    		
    		String curr = tokens.nextToken();    		
    		if (curr.equals("d")) {
    			height = Integer.parseInt(tokens.nextToken());
    			width = Integer.parseInt(tokens.nextToken());
    			depth = Integer.parseInt(tokens.nextToken());
    			System.out.println("height is "+height);
    			System.out.println("depth is "+depth);
    			System.out.println("width is "+width);
    		} else if (curr.equals("p")) {
    			long x1 = Integer.parseInt(tokens.nextToken());
    			long y1  = Integer.parseInt(tokens.nextToken());
    			long z1 = Integer.parseInt(tokens.nextToken());

    			long x2 = Integer.parseInt(tokens.nextToken());
    			long y2  = Integer.parseInt(tokens.nextToken());
    			long z2 = Integer.parseInt(tokens.nextToken());

    			Coordinate srcPtr = new Coordinate(x1, y1, z1);
    			Coordinate dstPtr = new Coordinate(x2, y2, z2);
    			Pair p = new Pair(srcPtr, dstPtr);
    			workListPtr.add(p);
    			srcVectorPtr.add(srcPtr);
    			dstVectorPtr.add(dstPtr);
    		}

        } /* iterate over lines in input file */

    	System.out.println("Pairs read "+srcVectorPtr.size());
        Grid gridPtr = new Grid(width, height, depth);
        mazePtr.gridPtr = gridPtr;
        for (Pair pair : workListPtr) {
        	mazePtr.workQueuePtr.add(pair);
        }
        Grid.addToGrid(gridPtr, wallVectorPtr, "wall");
        Grid.addToGrid(gridPtr, srcVectorPtr,  "source");
        Grid.addToGrid(gridPtr, dstVectorPtr,  "destination");
        
        return;
    }


    /* =============================================================================
     * maze_checkPaths
     * =============================================================================
     */
    static boolean
    maze_checkPaths (Maze mazePtr, ArrayList<ArrayList<Coordinate>> pathVectorListPtr, boolean doPrintPaths)
    {
        Grid gridPtr = mazePtr.gridPtr;
        long width  = gridPtr.width;
        long height = gridPtr.height;
        long depth  = gridPtr.depth;
        long i;

        /* Mark walls */
        Grid testGridPtr = new Grid(width, height, depth);
        Grid.grid_addPath(testGridPtr, mazePtr.wallVectorPtr);

        /* Mark sources */
        ArrayList<Coordinate> srcVectorPtr = mazePtr.srcVectorPtr;
        for (Coordinate srcPtr : srcVectorPtr) {
            Grid.grid_setPoint(testGridPtr, srcPtr.x, srcPtr.y, srcPtr.z, 0);
        }

        /* Mark destinations */
        ArrayList<Coordinate> dstVectorPtr = mazePtr.dstVectorPtr;
        for (Coordinate dstPtr : dstVectorPtr) {
            Grid.grid_setPoint(testGridPtr, dstPtr.x, dstPtr.y, dstPtr.z, 0);
        }

        /* Make sure path is contiguous and does not overlap */
        long id = 0;
        for (ArrayList<Coordinate> pathVectorPtr : pathVectorListPtr) {
        	for (Coordinate pointPtr : pathVectorPtr) {
                id++;
                /* Check start */
                Coordinate prevGridPointPtr = pathVectorPtr.get(0);
                prevGridPointPtr = Grid.grid_getPoint(gridPtr, prevGridPointPtr);
                                
            	int index = -1;
                for (Coordinate currGridPointPtr : pathVectorPtr) {
                	index++;
                    currGridPointPtr = Grid.grid_getPoint(gridPtr, currGridPointPtr);
                	
                    if (index == 0 || index == (pathVectorPtr.size() - 1)) {
                    	continue;
                    }

                    
                    if (!Coordinate.coordinate_areAdjacent(currGridPointPtr, prevGridPointPtr)) {
                        return false;
                    }
                    
                    long x = currGridPointPtr.x;
                    long y = currGridPointPtr.y;
                    long z = currGridPointPtr.z;
                    if (Grid.grid_getPoint(testGridPtr, x, y, z).value != Grid.GRID_POINT_EMPTY) {
                        return false;
                    } else {
                        Grid.grid_setPoint(testGridPtr, x, y, z, id);
                    }
                }
                /* Check end */
//                long* lastGridPointPtr = (long*)vector_at(pointVectorPtr, j);
//                grid_getPointIndices(gridPtr, lastGridPointPtr, &x, &y, &z);
//                if (grid_getPoint(testGridPtr, x, y, z) != 0) {
//                    return false;
//                }
            } /* iteratate over pathVector */
        } /* iterate over pathVectorList */

//        if (doPrintPaths) {
//            puts("\nRouted Maze:");
//            grid_print(testGridPtr);
//        }
//
        return true;
    }


    public static void main(String args[]) {
    	
    	Maze maze = new Maze();
    	try {
			Maze.maze_read(maze, "random-x256-y256-z3-n256.txt");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	Router router = new Router(1, 1, 2, 1);
    	ArrayList<ArrayList<Coordinate>> pathVectorListPtr = new ArrayList<ArrayList<Coordinate>>();
    	Router.router_solve(router, maze, pathVectorListPtr);
    	System.out.println("Paths added are "+pathVectorListPtr.size());
    	if (Maze.maze_checkPaths(maze, pathVectorListPtr, false)) {
    		System.out.println("Path is correct");
    	}
    }
}
